﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GameDataTempshitEditor.Widgets
{
    public partial class ClassTree : UserControl
    {
        public ClassTree()
        {
            InitializeComponent();
        }

        private Red.GameData.Raw.ReflectionData _Reflection;

        public void BindReflection( Red.GameData.Raw.ReflectionData reflection )
        {
            _Reflection = reflection;
            RefreshClassTree();
        }

        public bool ShowAllClasses
        {
            get
            {
                return checkShowAllClasses.Checked;
            }
            set
            {
                if (value != checkShowAllClasses.Checked)
                {
                    checkShowAllClasses.Checked = value;
                    RefreshClassTree();
                }
            }
        }

        public Red.GameData.Raw.ReflectionClass SelectedClass
        {
            get
            {
                return GetSelectedClass();
            }
            set
            {
                SetSelectedClass(value);
            }
        }

        //---------------------

        public delegate void ClassChangedHandler(object sender, ClassTreedEventArgs e);
        public event ClassChangedHandler OnClassChanged;
        public event ClassChangedHandler OnClassCreateNew;
        public event ClassChangedHandler OnClassActivated;

        //---------------------

        private class TreeNode_ReflectionClass : TreeNode, IReflectionClassProvider
        {
            public readonly Red.GameData.Raw.ReflectionClass _Class;

            Red.GameData.Raw.ReflectionClass IReflectionClassProvider.AsClass()
            {
                return _Class;
            }

            public TreeNode_ReflectionClass(Font font, Red.GameData.Raw.ReflectionClass cls)
                : base(cls.Name)
            {
                _Class = cls;

                // extract class flags
                if (cls.IsAbstract || cls.ClassKeyName != "")
                {
                    FontStyle style = font.Style;
                    if (cls.IsAbstract)
                        style |= FontStyle.Italic;
                    if (cls.KeyName != "")
                        style |= FontStyle.Bold;

                    NodeFont = new Font(font, font.Style | style);
                }

                // child classes
                foreach (var childClass in cls.Children)
                    Nodes.Add(new TreeNode_ReflectionClass(font, childClass));
            }
        }

        private void SetSelectedClass( Red.GameData.Raw.ReflectionClass theclass )
        {

        }

        private Red.GameData.Raw.ReflectionClass GetSelectedClass()
        {
            try
            {
                var node = (TreeNode_ReflectionClass)treeView1.SelectedNode;
                if (node != null)
                    return node._Class;
            }
            catch (Exception)
            {
            }

            return null;
        }

        private void classTree_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                var item = (TreeNode_ReflectionClass)e.Item;
                DoDragDrop(item._Class, DragDropEffects.Copy);
            }
        }

        private void RefreshClassTree()
        {
            treeView1.BeginUpdate();

            treeView1.Nodes.Clear();
            if (_Reflection != null)
            {
                var allClasses = (checkShowAllClasses.CheckState == CheckState.Checked);

                List<Red.GameData.Raw.ReflectionClass> rootClasses = new List<Red.GameData.Raw.ReflectionClass>();
                if (allClasses)
                {
                    // use the whole class tree
                    foreach (var cls in _Reflection.AllClasses)
                        if (cls.Value.Parent == null)
                            rootClasses.Add(cls.Value);
                }
                else
                {
                    // use the classes generating named objects only
                    foreach (var cls in _Reflection.AllClasses)
                    {
                        if (cls.Value.ClassKeyName != "")
                        {
                            rootClasses.Add(cls.Value);
                        }
                    }
                }

                foreach (var rootClass in rootClasses)
                    treeView1.Nodes.Add(new TreeNode_ReflectionClass(Font, rootClass));
            }

            treeView1.EndUpdate();
            treeView1.Refresh();

            button1.Enabled = false;
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            var selected = SelectedClass;

            if (OnClassChanged != null)
                OnClassChanged(this, new ClassTreedEventArgs(selected));

            // can we create the object ?
            button1.Enabled = (selected != null) && (selected.KeyName != "") && (!selected.IsAbstract);
        }

        private void treeView1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
                if (OnClassActivated != null)
                    OnClassActivated(this, new ClassTreedEventArgs(SelectedClass));
        }

        private void checkShowAllClasses_CheckedChanged(object sender, EventArgs e)
        {
            RefreshClassTree();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (OnClassCreateNew != null)
                OnClassCreateNew(this, new ClassTreedEventArgs(SelectedClass));
        }
    }

    public class ClassTreedEventArgs : EventArgs
    {
        public Red.GameData.Raw.ReflectionClass Class { get; private set; }

        public ClassTreedEventArgs(Red.GameData.Raw.ReflectionClass reflectionClass)
        {
            Class = reflectionClass;
        }
    }

    public interface IReflectionClassProvider
    {
        Red.GameData.Raw.ReflectionClass AsClass();
    }
}
